package services

import (
	"encoding/json"
	"errors"
	"fmt"
	"iot-base/common/cache"
	"iot-base/common/ctrltype"
	"main/onvifprotocol"
	"net"
	"strconv"
	"strings"

	"github.com/beevik/etree"
	"github.com/use-go/onvif"
	wsdiscovery "github.com/use-go/onvif/ws-discovery"
)

func initDevice(pCmd *ctrltype.CtrlCmd) (*onvifprotocol.CameraDevice, error) {
	// 获取设备信息.
	thing, err := cache.GetThing(pCmd.ThingID)
	if err != nil {
		return nil, err
	}
	params := thing.Params
	ip, ok := params["ip"]
	if !ok {
		return nil, errors.New("没有获取到设备IP")
	}
	username, ok := params["username"]
	if !ok {
		return nil, errors.New("没有获取到设备用户名")
	}
	pwd, ok := params["pswd"]
	if !ok {
		return nil, errors.New("没有获取到设备密码")
	}
	return onvifprotocol.NewCameraDevice(ip, username, pwd)
}

// GetProfiles 获取设备配置信息.
func GetProfiles(pCmd *ctrltype.CtrlCmd) (map[string]interface{}, error) {
	media, err := initDevice(pCmd)
	if err != nil {
		return nil, errors.New("登录设备失败")
	}
	ret, err := media.GetProfiles()
	test, _ := json.Marshal(ret)
	fmt.Println(string(test))
	resp := make([]map[string]interface{}, 0, len(ret))
	for _, v := range ret {
		value := v["Profiles"]
		temp := make(map[string]interface{})
		// 视频编码信息
		videoEncoder := make(map[string]interface{})
		VideoEncoderConfiguration := value["VideoEncoderConfiguration"].(map[string]interface{})
		if VideoEncoderConfiguration["Encoding"] == nil {
			continue
		}
		temp["Name"] = value["Name"] // 码流昵称
		temp["ProfileToken"] = value["token"]
		temp["VideoSource"] = value["VideoSourceConfiguration"] // 视频源配置
		temp["VideoEncoder"] = make(map[string]interface{})

		videoEncoder["Encoding"] = VideoEncoderConfiguration["Encoding"] // 编码
		Quality, _ := strconv.ParseFloat(VideoEncoderConfiguration["Quality"].(string), 10)
		videoEncoder["Quality"] = Quality                          // 编码
		videoEncoder["Token"] = VideoEncoderConfiguration["token"] // token
		// I帧间隔
		H264 := VideoEncoderConfiguration[VideoEncoderConfiguration["Encoding"].(string)].(map[string]interface{})
		GovLength, _ := strconv.Atoi(H264["GovLength"].(string))
		videoEncoder["GovLength"] = GovLength
		videoEncoder["Mpeg4Profile"] = H264[VideoEncoderConfiguration["Encoding"].(string)+"Profile"]

		// 速率控制
		RateControl := VideoEncoderConfiguration["RateControl"].(map[string]interface{})
		FrameRateLimit, _ := strconv.Atoi(RateControl["FrameRateLimit"].(string))
		videoEncoder["FrameRateLimit"] = FrameRateLimit // 帧速率限制
		EncodingInterval, _ := strconv.Atoi(RateControl["EncodingInterval"].(string))
		videoEncoder["EncodingInterval"] = EncodingInterval // 编码间隔
		BitrateLimit, _ := strconv.Atoi(RateControl["BitrateLimit"].(string))
		videoEncoder["BitrateLimit"] = BitrateLimit // 码率上限
		// 分辨率
		Resolution := VideoEncoderConfiguration["Resolution"].(map[string]interface{})
		Width, _ := strconv.Atoi(Resolution["Width"].(string))
		videoEncoder["ResolutionWidth"] = Width
		Height, _ := strconv.Atoi(Resolution["Height"].(string))
		videoEncoder["ResolutionHeight"] = Height
		temp["VideoEncoder"] = videoEncoder
		resp = append(resp, temp)
	}
	return map[string]interface{}{"list": resp}, err
}

// SetProfile 更新设备文件.
func SetProfile(pCmd *ctrltype.CtrlCmd) (map[string]interface{}, error) {
	media, err := initDevice(pCmd)
	if err != nil {
		return nil, err
	}
	return media.SetProfile(pCmd.Params)
}

// ScanOnvifIp 扫描局域网ONVIF协议的摄像头.
func ScanOnvifIp(pCmd *ctrltype.CtrlCmd) (map[string]interface{}, error) {
	inters, err := net.Interfaces()
	if err != nil {
		return nil, err
	}
	resp := make(map[string]interface{})
	for _, v := range inters {
		s := getIps(v.Name)
		if len(s) > 0 {
			return s, nil
		}
	}
	return resp, nil
}

func getIps(interfaceName string) map[string]interface{} {
	devices := wsdiscovery.SendProbe(interfaceName, nil, []string{"dn:" + onvif.NVT.String()}, map[string]string{"dn": "http://www.onvif.org/ver10/network/wsdl"})
	resp := make(map[string]interface{})
	for _, j := range devices {
		doc := etree.NewDocument()
		if err := doc.ReadFromString(j); err != nil {
			fmt.Errorf("%s", err.Error())
			return nil
		}
		endpoints := doc.Root().FindElement("./Body/ProbeMatches/ProbeMatch")
		xaddr := endpoints.SelectElement("XAddrs")
		ip := strings.Split(strings.Split(xaddr.Text(), " ")[0], "/")[2]
		uuid := endpoints.SelectElement("EndpointReference").SelectElement("Address").Text()
		resp[uuid] = ip
	}
	return resp
}

// ContinuousMove 连续移动.
func ContinuousMove(pCmd *ctrltype.CtrlCmd) (map[string]interface{}, error) {
	media, err := initDevice(pCmd)
	if err != nil {
		return nil, err
	}
	return media.ContinuousMove(pCmd.ThingID, pCmd.Params)
}

func StopMove(pCmd *ctrltype.CtrlCmd) (map[string]interface{}, error) {
	media, err := initDevice(pCmd)
	if err != nil {
		return nil, err
	}
	return media.StopMove(pCmd.Params)
}

func RelativeZoomMove(pCmd *ctrltype.CtrlCmd) (map[string]interface{}, error) {
	media, err := initDevice(pCmd)
	if err != nil {
		return nil, err
	}
	return media.RelativeZoomMove(pCmd.ThingID, pCmd.Params)
}

func GetPresets(pCmd *ctrltype.CtrlCmd) (map[string]interface{}, error) {
	resp := make(map[string]interface{})
	media, err := initDevice(pCmd)
	if err != nil {
		return resp, err
	}
	list, err := media.GetPresets(pCmd.Params)
	if err != nil {
		return resp, err
	}
	resp["list"] = list
	return resp, nil
}

func SetPreset(pCmd *ctrltype.CtrlCmd) (map[string]interface{}, error) {
	resp := make(map[string]interface{})
	media, err := initDevice(pCmd)
	if err != nil {
		return resp, err
	}
	setPresetResp, err := media.SetPreset(pCmd.Params)
	if err != nil {
		return resp, err
	}
	return setPresetResp, nil
}

func GotoPreset(pCmd *ctrltype.CtrlCmd) (map[string]interface{}, error) {
	resp := make(map[string]interface{})
	media, err := initDevice(pCmd)
	if err != nil {
		return resp, err
	}
	_, err = media.GotoPreset(pCmd.Params)
	if err != nil {
		return resp, err
	}
	return resp, nil
}

func RemovePreset(pCmd *ctrltype.CtrlCmd) (map[string]interface{}, error) {
	resp := make(map[string]interface{})
	media, err := initDevice(pCmd)
	if err != nil {
		return resp, err
	}
	_, err = media.RemovePreset(pCmd.Params)
	if err != nil {
		return resp, err
	}
	return resp, nil
}

func FocusMove(pCmd *ctrltype.CtrlCmd) (map[string]interface{}, error) {
	resp := make(map[string]interface{})
	media, err := initDevice(pCmd)
	if err != nil {
		return resp, err
	}
	err = media.FocusMove(pCmd.Params)
	if err != nil {
		return resp, err
	}
	return resp, nil
}
